use std::rc::Rc;

use super::{node::Node, object::Object, syntaxResult::SyntaxResult, token::SyntaxToken};

#[derive(Debug)]
pub enum SyntaxExpression {
    Binary(BinaryExpression),
    Grouping(GroupingExpression),
    Unary(UnaryExpression),
    Call(CallExpression),
    Logical(LogicalExpression),
    Literal(LiteralExpression),
    Variable(VariableExpression),
    Assignment(AssignmentExpression),
}

impl SyntaxExpression {
    pub fn accept<T>(&self, visitor: &dyn ExpressionVisitor<T>) -> Result<T, SyntaxResult> {
        match self {
            Self::Binary(binary) => binary.accept(visitor),
            Self::Grouping(grouping) => grouping.accept(visitor),
            Self::Unary(unary) => unary.accept(visitor),
            Self::Call(call) => call.accept(visitor),
            Self::Literal(literal) => literal.accept(visitor),
            Self::Logical(logical) => logical.accept(visitor),
            Self::Variable(var) => var.accept(visitor),
            Self::Assignment(assign) => assign.accept(visitor),
        }
    }
}
#[derive(Debug)]
pub struct BinaryExpression {
    pub left: Box<SyntaxExpression>,
    pub operator: SyntaxToken,
    pub right: Box<SyntaxExpression>,
}
#[derive(Debug)]
pub struct GroupingExpression {
    pub expression: Box<SyntaxExpression>,
}
#[derive(Debug)]
pub struct LiteralExpression {
    pub value: Option<Object>,
}
#[derive(Debug)]
pub struct UnaryExpression {
    pub operator: SyntaxToken,
    pub right: Box<SyntaxExpression>,
}
#[derive(Debug)]
pub struct ProgramExpression {}

//变量表达式;
#[derive(Debug)]
pub struct VariableExpression {
    pub name: SyntaxToken,
}

//赋值表达式;
#[derive(Debug)]
pub struct AssignmentExpression {
    pub name: SyntaxToken,
    pub value: Box<SyntaxExpression>,
}
#[derive(Debug)]
pub struct LogicalExpression {
    pub left: Box<SyntaxExpression>,
    pub operator: SyntaxToken,
    pub right: Box<SyntaxExpression>,
}
#[derive(Debug)]
pub struct CallExpression {
    pub callee: Rc<SyntaxExpression>,
    pub paren: SyntaxToken,
    pub arguments: Vec<SyntaxExpression>,
}
pub trait ExpressionVisitor<T> {
    fn visitBinaryExpression(&self, expr: &BinaryExpression) -> Result<T, SyntaxResult>;
    fn visitGroupingExpression(&self, expr: &GroupingExpression) -> Result<T, SyntaxResult>;
    fn visitLiteralExpression(&self, expr: &LiteralExpression) -> Result<T, SyntaxResult>;
    fn visitUnaryExpression(&self, expr: &UnaryExpression) -> Result<T, SyntaxResult>;
    fn visitCallExpression(&self, expr: &CallExpression) -> Result<T, SyntaxResult>;
    fn visitProgramExpression(&self, expr: &ProgramExpression) -> Result<T, SyntaxResult>;
    fn visitVariableExpression(&self, expr: &VariableExpression) -> Result<T, SyntaxResult>;
    fn visitAssignmentExpression(&self, expr: &AssignmentExpression) -> Result<T, SyntaxResult>;
    fn visitLogicalExpression(&self, expr: &LogicalExpression) -> Result<T, SyntaxResult>;
}

impl BinaryExpression {
    fn accept<T>(&self, visitor: &dyn ExpressionVisitor<T>) -> Result<T, SyntaxResult> {
        visitor.visitBinaryExpression(self)
    }
}
impl GroupingExpression {
    fn accept<T>(&self, visitor: &dyn ExpressionVisitor<T>) -> Result<T, SyntaxResult> {
        visitor.visitGroupingExpression(self)
    }
}
impl LiteralExpression {
    fn accept<T>(&self, visitor: &dyn ExpressionVisitor<T>) -> Result<T, SyntaxResult> {
        visitor.visitLiteralExpression(self)
    }
}
impl UnaryExpression {
    fn accept<T>(&self, visitor: &dyn ExpressionVisitor<T>) -> Result<T, SyntaxResult> {
        visitor.visitUnaryExpression(self)
    }
}
impl VariableExpression {
    fn accept<T>(&self, visitor: &dyn ExpressionVisitor<T>) -> Result<T, SyntaxResult> {
        visitor.visitVariableExpression(self)
    }
}

impl AssignmentExpression {
    fn accept<T>(&self, visitor: &dyn ExpressionVisitor<T>) -> Result<T, SyntaxResult> {
        visitor.visitAssignmentExpression(self)
    }
}
impl LogicalExpression {
    fn accept<T>(&self, visitor: &dyn ExpressionVisitor<T>) -> Result<T, SyntaxResult> {
        visitor.visitLogicalExpression(self)
    }
}
impl CallExpression {
    fn accept<T>(&self, visitor: &dyn ExpressionVisitor<T>) -> Result<T, SyntaxResult> {
        visitor.visitCallExpression(self)
    }
}